package com.online.websocketcluster.conf;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.online.websocketcluster.entity.HbEntity;
import com.online.websocketcluster.entity.SessionEntity;
import com.online.websocketcluster.entity.SessionObj;
import com.online.websocketcluster.service.FindAgentService;
import com.online.websocketcluster.service.MessageBatchService;
import com.online.websocketcluster.service.SessionManageService;
import com.online.websocketcluster.service.WxInterfaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

import static com.online.websocketcluster.util.HbUtils.HBMAPS;
import static java.lang.System.out;

/**
 * WebSocket 服务器的端点
 *
 * @author hsc
 * @create 2018-04-25 16:23
 */
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServerEndpoint {

    @Autowired
    SessionManageService sessionManageService;

    @Autowired
    FindAgentService findAgentService;

    @Autowired
    WxInterfaceService wxInterfaceService;

    @Autowired
    MessageBatchService messageBatchService;

    /**
     * 自定义工具类 解决@Autowired为null
     */
    public static WebSocketServerEndpoint webSocketServerEndpoint;

    @PostConstruct
    public void init() {
        webSocketServerEndpoint = this;
    }

    /**
     * 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的
     */
    private static int onlineCount = 0;

    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象
     */
    private static CopyOnWriteArraySet<WebSocketServerEndpoint> webSocketSet = new CopyOnWriteArraySet<WebSocketServerEndpoint>();

    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    private int serviceId;


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        //加入set中
        webSocketSet.add(this);
        //在线数加1
        addOnlineCount();
        out.println("有新连接加入！当前在线人数为" + getOnlineCount());
//        try {
//            sendMessage("hello");
//        } catch (IOException e) {
//            out.println("IO异常");
//        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        //从set中删除
        webSocketSet.remove(this);

        if (serviceId > 0) {
            // 删除HSMAPS心跳集合对应的值
            HBMAPS.remove(serviceId);
            // 删除redis缓存
            Map restMap = new HashMap(2);
            restMap.put("service_id", serviceId);
            webSocketServerEndpoint.sessionManageService.delWsAddress(restMap);
        }
        //在线数减1
        subOnlineCount();
        out.println("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        out.println("来自客户端的消息:" + message);
        JSONObject json = JSONObject.parseObject(message);

        String header = json.getString("header");

        String body = json.getString("body");

        JSONObject headerJson = JSONObject.parseObject(header);

        JSONObject bodyJson = JSONObject.parseObject(body);

        // 客服ID
        int serviceId = headerJson.getInteger("service_id");
        // 会话ID
        Long sessionId = bodyJson.getLong("session_id");
        // 企业ID
        int eId = headerJson.getInteger("e_id");
        // 消息类型
        String cmd = headerJson.getString("cmd");
        // token
        String token = headerJson.getString("token");

        Map restMap = new HashMap(10);
        restMap.put("service_id", serviceId);
        restMap.put("session_id", sessionId);
        restMap.put("e_id", eId);

        this.serviceId = serviceId;

        switch (cmd) {
            // token校验命令
            case "auth_req":

                token = bodyJson.getString("token");
                restMap.put("token", token);
                Map authReqMap = webSocketServerEndpoint.sessionManageService.checkToken(restMap);
                int authReqResult = 0;
                //(int) authReqMap.get("result");
                try {
                    JSONObject authBodyJson = new JSONObject();
                    authBodyJson.put("result", authReqResult);
                    JSONObject authHeaderJson = new JSONObject();
                    authHeaderJson.put("service_id", serviceId);
                    authHeaderJson.put("e_id", eId);
                    authHeaderJson.put("token", token);
                    authHeaderJson.put("cmd", "auth_resp");

                    JSONObject authReqJson = new JSONObject();
                    authReqJson.put("header", authHeaderJson);
                    authReqJson.put("body", authBodyJson);

                    // token校验应答
                    sendMessage(authReqJson.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }

                // token校验成功 保存坐席websocket服务地址 保存心跳到HBMAPS
                if (0 == authReqResult) {
                    restMap.put("address", "websocket-cluster");
                    Map saveResult = webSocketServerEndpoint.sessionManageService.saveWsAddress(restMap);
                    Long nowTime = System.currentTimeMillis();
                    HbEntity hbEntity = new HbEntity(nowTime, session, this);
                    HBMAPS.put(serviceId, hbEntity);
                }

                break;

            //  坐席请求未读消息
            case "msg_req":

                Map messagesMap = webSocketServerEndpoint.sessionManageService.getMessages(restMap);
                List<String> messages = (List<String>) messagesMap.get("messages");
                JSONObject msgHeaderJson = new JSONObject();
                JSONObject msgBodyJson = new JSONObject();
                JSONObject msgJson = new JSONObject();
                msgHeaderJson.put("service_id", serviceId);
                msgHeaderJson.put("e_id", eId);
                msgHeaderJson.put("token", token);
                msgHeaderJson.put("cmd", "msg_resp");
                msgBodyJson.put("Messages", messages);
                msgBodyJson.put("session_id", sessionId);
                msgJson.put("header", msgHeaderJson);
                msgJson.put("body", msgBodyJson);
                // 坐席请求未读消息回复
                try {
                    sendMessage(msgJson.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;

            //  坐席告知服务器读取了哪些消息
            case "msgisread":
                // 消息ID集合
                String msgIds = bodyJson.getString("msg_ids");
                Map msgIdMap = new HashMap(2);
                msgIdMap.put("uuids", msgIds.split(","));
                msgIdMap.put("e_id", eId);
                // 保存已读的uuid到批处理服务
             //   Map loadMessageMap = webSocketServerEndpoint.messageBatchService.saveUuids(msgIdMap);
                int loadMessageResult =0; //(int) loadMessageMap.get("result");
                // 0：成功 1：失败
                if (loadMessageResult == 0) {

                }
                break;

            //  心跳
            case "hb":
                // 流水号
                int seq = bodyJson.getInteger("seq");

                // 根据id取出系统心跳管理集合的心跳
                HbEntity hbEntity = HBMAPS.get(serviceId);

                if (null == hbEntity) {
                    // 超时调用删除websocket服务地址接口
                    webSocketServerEndpoint.sessionManageService.delWsAddress(restMap);

                    // 关闭会话
                    try {
                        session.close();

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                } else {
                    // 更新hb-time
                    hbEntity.setHbTime(System.currentTimeMillis());
                    HBMAPS.put(serviceId, hbEntity);

                    JSONObject seqJson = new JSONObject();
                    JSONObject seqHeaderJson = new JSONObject();
                    JSONObject seqBodyJson = new JSONObject();
                    seqHeaderJson.put("service_id", serviceId);
                    seqHeaderJson.put("e_id", eId);
                    seqHeaderJson.put("cmd", "hb_resp");
                    seqHeaderJson.put("token", token);
                    seqBodyJson.put("seq", seq);
                    seqJson.put("header", seqHeaderJson);
                    seqJson.put("body", seqBodyJson);
                    // 心跳回复
                    try {
                        sendMessage(seqJson.toString());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }


                break;

            // 坐席关闭与顾客的聊天会话
            case "close_session_req":
                JSONArray session_obj = bodyJson.getJSONArray("session_obj");
                restMap.put("session_obj", session_obj);
                Map closeSessionMap = webSocketServerEndpoint.findAgentService.closeChatSession(restMap);
                int closeResult = (int) closeSessionMap.get("result");
                JSONObject closeJson = new JSONObject();
                JSONObject closeHeaderJson = new JSONObject();
                JSONObject closeBodyJson = new JSONObject();
                closeHeaderJson.put("service_id", serviceId);
                closeHeaderJson.put("e_id", eId);
                closeHeaderJson.put("cmd", "close_session_resp");
                closeHeaderJson.put("token", token);
                closeBodyJson.put("result", closeResult);
                closeJson.put("header", closeHeaderJson);
                closeJson.put("body", closeBodyJson);
                // 坐席关闭与顾客的聊天会话回复
                try {
                    sendMessage(closeJson.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }

                // 查找待接入顾客
                Map waitUserParams = new HashMap(2);
                waitUserParams.put("service_id", serviceId);
                waitUserParams.put("e_id", eId);
                Map waitUserMap = webSocketServerEndpoint.findAgentService.findWaitUser(waitUserParams);
                String waitOpenId = (String) waitUserMap.get("open_id");
                Long waitSessionId = (Long) waitUserMap.get("session_id");
                int waitResult = (int) waitUserMap.get("result");

                JSONObject waitJson = new JSONObject();
                JSONObject waitHeaderJson = new JSONObject();
                JSONObject waitBodyJson = new JSONObject();

                waitHeaderJson.put("service_id", serviceId);
                waitHeaderJson.put("e_id", eId);
                waitHeaderJson.put("cmd", "close_session_resp");
                waitHeaderJson.put("token", token);
                waitBodyJson.put("open_id", waitOpenId);
                waitBodyJson.put("session_id", waitSessionId);
                waitBodyJson.put("result", waitResult);
                waitJson.put("header", waitHeaderJson);
                waitJson.put("body", waitBodyJson);

                try {
                    sendMessage(waitJson.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }

                break;
            // 坐席发送聊天信息
            case "send_msg":
                String sendSeq = bodyJson.getString("seq");
                String sendOpenId = bodyJson.getString("open_id");
                int msgType = bodyJson.getInteger("msg_type");
                Map msgMap = null;
                if (msgType == 1) {
                    // 消息内容
                    String content = bodyJson.getString("content");
                    Map messageMap = new HashMap(2);
                    messageMap.put("open_id", sendOpenId);
                    messageMap.put("content", content);
                    msgMap = webSocketServerEndpoint.wxInterfaceService.sendText(messageMap);
                } else if (msgType == 2) {
                    // 发送的图片的媒体ID
                    String mediaId = bodyJson.getString("media_id");
                    // 图片url
                    String url = bodyJson.getString("url");
                    Map messageMap = new HashMap(2);
                    messageMap.put("open_id", sendOpenId);
                    messageMap.put("media_id", mediaId);
                    msgMap = webSocketServerEndpoint.wxInterfaceService.sendImage(messageMap);
                }

                int msgResult = (int) msgMap.get("result");
                JSONObject respJson = new JSONObject();
                JSONObject respHeaderJson = new JSONObject();
                JSONObject respBodyJson = new JSONObject();
                respBodyJson.put("seq", sendSeq);
                respBodyJson.put("result", msgResult);
                respHeaderJson.put("cmd", "send_msg_resp");
                respHeaderJson.put("e_id", eId);
                respHeaderJson.put("service_id", serviceId);
                respHeaderJson.put("token", token);
                respJson.put("header", respHeaderJson);
                respJson.put("body", respBodyJson);

                // 坐席发送聊天信息回复
                try {
                    sendMessage(respJson.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;

            //坐席同步会话状态
            case "sync_req":
                Map syncMap = webSocketServerEndpoint.sessionManageService.getSessionList(restMap);
                // 当前会话数量
                int results = (int) syncMap.get("results");
                // 会话对象
                Object sessionObj = syncMap.get("session_obj");
                JSONObject syncJson = new JSONObject();
                JSONObject syncHeaderJson = new JSONObject();
                JSONObject syncBodyJson = new JSONObject();

                syncBodyJson.put("results", results);
                syncBodyJson.put("session_obj", sessionObj);
                syncHeaderJson.put("e_id", eId);
                syncHeaderJson.put("cmd", "sync_resp");
                syncHeaderJson.put("token", token);
                syncHeaderJson.put("service_id", serviceId);
                syncJson.put("header", syncHeaderJson);
                syncJson.put("body", syncBodyJson);
                // 坐席同步会话回复
                try {
                    sendMessage(syncJson.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }


    }


    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        out.println("发生错误");
        error.printStackTrace();
    }


    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }


    /**
     * 群发自定义消息
     */
    public static void sendInfo(String message) throws IOException {
        for (WebSocketServerEndpoint item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServerEndpoint.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServerEndpoint.onlineCount--;
    }
}
